package org.anachronos.jeep.ui.attach;

import java.io.File;
import java.util.ArrayList;

import org.anachronos.jeep.core.config.ConfigFactory;
import org.anachronos.jeep.core.config.impl.Config;
import org.anachronos.jeep.ui.JeepUiPlugin;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;

public class NewAttachmentWizard 
	extends Wizard {

	public class ConfigLabelProvider 
			extends LabelProvider 
			implements ITableLabelProvider  {
		private Config config;
		
		void setConfig(final Config config) {
			this.config = config;
		}
		
		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		@Override
		public String getColumnText(Object element, int columnIndex) {
			switch (columnIndex) {
			case 0:
				return element.toString();
			default:
				return config.getIncludes().contains(element) ? 
						"Includes" : "Excludes";
			}
		}
	}
	
	private SelectConfigFileWizardPage selectConfigPage;
	private ShowProfilerConfigWizardPage showProfilerConfigPage;
	private Config config;
	private String configFile;
	
	public NewAttachmentWizard() {
		super();
		setDialogSettings(JeepUiPlugin.getDefault().getDialogSettings());
	}
	
	@Override
	public boolean performFinish() {
		return true;
	}

	@Override
	public void addPages() {
		setWindowTitle("Attach Profiler...");
		setNeedsProgressMonitor(false);
		selectConfigPage = new SelectConfigFileWizardPage();
		addPage(selectConfigPage);
		
		showProfilerConfigPage = new ShowProfilerConfigWizardPage();
		addPage(showProfilerConfigPage);
	}
	
	public String getConfigFile() {
		return configFile;
	}
	
	Config getConfig() {
		return config;
	}
	
	public void loadConfigFile(final String configFile) throws Exception {
		config = ConfigFactory.load(configFile);
		this.configFile = configFile;
	}
	
	class SelectConfigFileWizardPage extends WizardPage {
		private static final String DIALOG_SETTINGS_CONFIG_FILE = "configFile";
		private static final String DIALOG_SETTINGS_SELECT_CONFIG_TEMPLATE = "selectConfigTemplate";
		
		private Text configFileText;
		private Combo configTemplateCombo;
		private Button selectConfigFile;
		private Button selectConfigTemplate;

		protected SelectConfigFileWizardPage() {
			super(SelectConfigFileWizardPage.class.getSimpleName());
			setTitle("Select profiler config");
			setDescription("Select a profiler config template or an existing profiler config file.");
		}
		
		@Override
		public void createControl(final Composite parent) {
			final Composite composite = new Composite(parent, SWT.NONE);
			final GridLayout layout = new GridLayout(3, false);
			composite.setLayout(layout);
			setControl(composite);
			final IDialogSettings settings = getDialogSettings();
			
			selectConfigTemplate = new Button(composite, SWT.RADIO);
			selectConfigTemplate.setText("Profiler config template:");
			selectConfigTemplate.setLayoutData(GridDataFactory.swtDefaults().create());
			
			configTemplateCombo = new Combo(composite, SWT.READ_ONLY);
			configTemplateCombo.setItems(new String[] {"Eclipse", "JBoss"});
			configTemplateCombo.select(0);
			configTemplateCombo.setLayoutData(GridDataFactory.swtDefaults().
					span(2, 1).align(SWT.FILL, SWT.CENTER).create());

			selectConfigTemplate.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(final SelectionEvent e) {
					configTemplateCombo.setEnabled(selectConfigTemplate.getSelection());
				}
			});
			
			selectConfigFile = new Button(composite, SWT.RADIO);
			selectConfigFile.setText("Profiler config file:");
			selectConfigFile.setLayoutData(GridDataFactory.swtDefaults().create());
			
			configFileText = new Text(composite, SWT.SINGLE|SWT.BORDER);
			configFileText.setLayoutData(GridDataFactory.swtDefaults().
					align(SWT.FILL, SWT.CENTER).grab(true, false).create());
			configFileText.setEnabled(false);
			final String dialogSettingsConfigFile = settings.get(DIALOG_SETTINGS_CONFIG_FILE);
			configFileText.setText(dialogSettingsConfigFile == null ? "" : dialogSettingsConfigFile);
			configFileText.addModifyListener(new ModifyListener() {				
				@Override
				public void modifyText(ModifyEvent _) {
					handleConfigFileTextChange();
				}
			});
			configFileText.addFocusListener(new FocusAdapter() {
				@Override
				public void focusGained(FocusEvent _) {
				}
			});
			
			final Button browseFileButton = new Button(composite, SWT.PUSH);
			browseFileButton.setText("Browse...");
			browseFileButton.setLayoutData(GridDataFactory.swtDefaults().create());
			browseFileButton.setEnabled(false);
			
			browseFileButton.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(final SelectionEvent e) {
					final FileDialog fileDialog = new FileDialog(getShell(), SWT.OPEN);
					fileDialog.setFilterExtensions(new String[] { "*.config" });
					final String configFile = configFileText.getText();
					if (configFile != null && new File(configFile).exists()) {
						fileDialog.setFileName(configFile);
					}
					final String file = fileDialog.open();
					if (file != null) {
						configFileText.setText(file);
					}
				}
			});
			
			selectConfigFile.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(final SelectionEvent e) {
					handleCheckboxChange(browseFileButton);
					handleConfigFileTextChange();
				}
			});
			final boolean configTemplate = settings.getBoolean(DIALOG_SETTINGS_SELECT_CONFIG_TEMPLATE);
			selectConfigTemplate.setSelection(configTemplate);
			selectConfigFile.setSelection(!configTemplate);
			handleCheckboxChange(browseFileButton);
			handleConfigFileTextChange();
		}

		@Override
		public void setPageComplete(boolean complete) {
			final IDialogSettings settings = getDialogSettings();
			settings.put(DIALOG_SETTINGS_SELECT_CONFIG_TEMPLATE, selectConfigTemplate.getSelection());
			settings.put(DIALOG_SETTINGS_CONFIG_FILE, configFileText.getText());
			
			super.setPageComplete(complete);
		}
		
		private void handleCheckboxChange(final Button browseFileButton) {
			final boolean selection = selectConfigFile.getSelection();
			configFileText.setEnabled(selection);
			browseFileButton.setEnabled(selection);
		}
		
		private void handleConfigFileTextChange() {
			if (configFileText.isEnabled()) {
				final String configFile = configFileText.getText();
				final boolean configFileExists = configFile != null 
					&& new File(configFile).exists();
				if (configFileExists) {
					final NewAttachmentWizard wizard = 
						(NewAttachmentWizard) getWizard();
					try {
						final String configFile1 = configFileText.getText();
						wizard.loadConfigFile(configFile1);
						
						setPageComplete(true);
						setErrorMessage(null);
					} catch (final Exception e) {
						setPageComplete(false);
						setErrorMessage("Can't load profiler config file!");
					}
				} else {
					setPageComplete(false);
					setErrorMessage("Profiler config file doesn't exist!");
				}
			} else {
				setPageComplete(true);
				setErrorMessage(null);
			}
		}		
	}
	
	class ShowProfilerConfigWizardPage extends WizardPage {
		private final class ConfigContentProvider implements
				IStructuredContentProvider {
			private Config config;

			@Override
			public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
				config = (Config) newInput;
				final TableViewer tableViewer = (TableViewer) viewer;
				final ConfigLabelProvider labelProvider = 
					(ConfigLabelProvider) tableViewer.getLabelProvider();
				labelProvider.setConfig(config);
			}

			@Override
			public void dispose() {
			}

			@Override
			public Object[] getElements(Object _) {
				final ArrayList<String> filter = new ArrayList<String>(config.getIncludes());
				filter.addAll(config.getExcludes());
				return filter.toArray();
			}
		}


		private TableViewer filterViewer;
		private Button transactionTracingButton;
		private Button jdbcTracingButton;

		public ShowProfilerConfigWizardPage() {
			super(ShowProfilerConfigWizardPage.class.getSimpleName());
			setTitle("Review profiler config");
			setDescription("You can edit the selected profiler config.");
		}
		

		public void setVisible(final boolean visible) {
			if (visible) {
				final NewAttachmentWizard wizard = (NewAttachmentWizard) getWizard();
				final Config config = wizard.getConfig();
				filterViewer.setInput(config);
				jdbcTracingButton.setSelection(config.isEnableJdbcTracing());
				transactionTracingButton.setSelection(config.isEnableTransactionTracing());
			}
			super.setVisible(visible);
		}

		@Override
		public void createControl(final Composite parent) {
			final Composite composite = new Composite(parent, SWT.NONE);
			composite.setLayout(new GridLayout(2, false));
			setControl(composite);
			
			final Composite tableParent = new Composite(composite, SWT.NONE);
			final TableColumnLayout layout = new TableColumnLayout();
			tableParent.setLayout(layout);
			filterViewer = new TableViewer(tableParent);
			filterViewer.getTable().setHeaderVisible(true);
			filterViewer.setContentProvider(new ConfigContentProvider());
			filterViewer.setLabelProvider(new ConfigLabelProvider());
			
			tableParent.setLayoutData(GridDataFactory.swtDefaults()
					.align(SWT.FILL, SWT.FILL).grab(true, true).span(1, 3).create());
			final TableColumn filterColumn = createColumn("Filter", true);
			layout.setColumnData(filterColumn, new ColumnWeightData(80, true));
			
			final TableColumn typeColumn = createColumn("Type", false);
			layout.setColumnData(typeColumn, new ColumnPixelData(100));
			
			final GridDataFactory buttonDridDataFactory = GridDataFactory.swtDefaults()
				.align(SWT.FILL, SWT.BEGINNING);
			
			final Button addButton = new Button(composite, SWT.PUSH|SWT.LEFT);
			addButton.setText("Add...");
			buttonDridDataFactory.applyTo(addButton);
			
			final Button editButton = new Button(composite, SWT.PUSH|SWT.LEFT);
			editButton.setText("Edit...");
			editButton.setEnabled(false);
			buttonDridDataFactory.applyTo(editButton);
			
			final Button removeButton = new Button(composite, SWT.PUSH|SWT.LEFT);
			removeButton.setText("Remove");
			removeButton.setEnabled(false);
			buttonDridDataFactory.applyTo(removeButton);
			final Group group = new Group(composite, SWT.SHADOW_ETCHED_IN);
			group.setText("Tracing Options");
			group.setLayoutData(GridDataFactory.swtDefaults()
					.align(SWT.FILL, SWT.END).grab(true, false).span(2, 1).create());
			group.setLayout(new GridLayout(1, false));
			
			final GridDataFactory checkBoxGridDataFactory = GridDataFactory.swtDefaults()
				.align(SWT.BEGINNING, SWT.BEGINNING);
			
			jdbcTracingButton = new Button(group, SWT.CHECK);
			jdbcTracingButton.setText("Enable JDBC Tracing");
			checkBoxGridDataFactory.applyTo(jdbcTracingButton);

			transactionTracingButton = new Button(group, SWT.CHECK);
			transactionTracingButton.setText("Enable Transaction Tracing");
			checkBoxGridDataFactory.applyTo(transactionTracingButton);

			filterViewer.addSelectionChangedListener(new ISelectionChangedListener() {
				@Override
				public void selectionChanged(SelectionChangedEvent event) {
					final boolean selectionNotEmpty = !event.getSelection().isEmpty();
					editButton.setEnabled(selectionNotEmpty);
					removeButton.setEnabled(selectionNotEmpty);
				}
			});
		}
		

		private TableColumn createColumn(final String text, final boolean resizable) {
			final TableColumn column = new TableColumn(filterViewer.getTable(), SWT.LEFT);
			if (text != null) {
				column.setText(text);
			}
			column.setResizable(resizable);
			column.setMoveable(resizable);
			return column;
		}
	}
}
